package cn.admin.configcenter.registry.service.push;

import cn.admin.configcenter.registry.common.event.Event;
import cn.admin.configcenter.registry.common.event.EventListener;
import cn.admin.configcenter.registry.common.event.Events;
import cn.admin.configcenter.registry.common.info.ClientConnection;
import cn.admin.configcenter.registry.common.info.GroupId;
import cn.admin.configcenter.registry.service.PushDataService;

import java.util.ArrayList;
import java.util.List;

public class DefaultPushService extends EventListener implements PushDataService {

    private static final int DEFAULT_PUSH_MGR_SIZE = 2;
    private final PushTaskManager[] defaultPushTaskManagers;

    public DefaultPushService() {
        this.defaultPushTaskManagers = new PushTaskManager[DEFAULT_PUSH_MGR_SIZE];

        for (int i = 0;i < DEFAULT_PUSH_MGR_SIZE;i ++) {
            defaultPushTaskManagers[i] = new PushTaskManager("Default-" + i);
        }
    }

    @Override
    public List<Class<? extends Event>> interest() {
        List<Class<? extends Event>> types = new ArrayList<>();
        types.add(Events.GroupDataChangedEvent.class);
        types.add(Events.SubscriberAddedEvent.class);
        return types;
    }

    @Override
    public void onEvent(Event event) {
        if (event instanceof Events.GroupDataChangedEvent) {
            Events.GroupDataChangedEvent gdce = (Events.GroupDataChangedEvent) event;
            this.scheduleAllPush(gdce.group);
        } else if (event instanceof Events.SubscriberAddedEvent) {
            Events.SubscriberAddedEvent sae = (Events.SubscriberAddedEvent) event;
            this.scheduleSinglePush(sae.group,sae.client);
        }
    }

    @Override
    public void scheduleSinglePush(GroupId group, ClientConnection dest) {
        if (dest.getConnection().isConnected()) {
            PushDelayTask task = new PushDelayTask(group,dest);
            this.assignToPushManager(task,group.dataId);
        }
    }

    @Override
    public void scheduleAllPush(GroupId group) {
        PushDelayTask task = new PushDelayTask(group);
        this.assignToPushManager(task,group.dataId);
    }

    @Override
    public String getTaskCount() {
        StringBuffer sb = new StringBuffer();
        sb.append("\n");

        for(int i = 0; i < this.defaultPushTaskManagers.length; ++i) {
            sb.append("defTaskCount-" + (i + 1) + "=").
                    append(this.defaultPushTaskManagers[i].getHistoryTasks());
            if (i + 1 < this.defaultPushTaskManagers.length) {
                sb.append(",");
            }
        }

        return sb.toString();
    }

    @Override
    public String getPendingPushCount() {
        StringBuffer sb = new StringBuffer();
        long otherPendingTask = 0L;
        sb.append("\n");

        for(int i = 0; i < this.defaultPushTaskManagers.length; ++i) {
            long temp = (long)this.defaultPushTaskManagers[i].taskCount();
            sb.append("defPendingCount-" + (i + 1) + "=").append(temp);
            if (i + 1 < this.defaultPushTaskManagers.length) {
                sb.append(",");
            }

            otherPendingTask += temp;
        }

        sb.append(",totalPendingCount=").append(otherPendingTask);
        return sb.toString();
    }

    private void assignToPushManager(PushDelayTask task,String dataId) {
        PushTaskManager pushTaskManager = this.getPushTaskManager(dataId);
        pushTaskManager.addTask(task);
        task.pushProfileTime.inQueueTime = System.currentTimeMillis();
    }

    private PushTaskManager getPushTaskManager(String dataId) {
        int idx = dataId.hashCode() & this.defaultPushTaskManagers.length - 1;
        return this.defaultPushTaskManagers[idx];
    }
}
